/*
 * ImmediateCrypt
 * Copyright (C) 2012 Giacomo Drago
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * http://giacomodrago.com/go/immediatecrypt
 * 
 */

package com.giacomodrago.immediatecrypt.messagecipher;

import com.giacomodrago.immediatecrypt.aes.AESEncryptedMessage;
import com.giacomodrago.immediatecrypt.aes.AESFacade;
import com.giacomodrago.immediatecrypt.aes.AESFacadeFactory;
import com.giacomodrago.immediatecrypt.aes.EncryptionException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.Charsets;

public class MessageCipher {

    private final static String MESSAGE_HEADER = "IMCR";
    
    private final AESFacade aes = AESFacadeFactory.getFacade();

    public String encrypt(String source, String password) {

        source = source.trim();
        byte[] plaintext;
        
        plaintext = Compression.compress(source.getBytes(Charsets.UTF_8));
        
        AESEncryptedMessage encryptedMessage;

        try {
            encryptedMessage = aes.encrypt(plaintext, password);
        } catch (EncryptionException ex) {
            return null;
        }

        String salt = encryptedMessage.getSalt();
        byte[] iv = encryptedMessage.getIv();
        byte[] ciphertext = encryptedMessage.getCiphertext();

        StringBuilder message = new StringBuilder();

        String iv_base64 = Base64.encodeBase64String(iv);
        String ciphertext_base64 = new String(
                Base64.encodeBase64(ciphertext, true));

        message.append(MESSAGE_HEADER)
            .append(';')
            .append(salt)
            .append(';')
            .append(iv_base64)
            .append(';')
            .append('\n')
            .append(ciphertext_base64);

        return message.toString();

    }

    public String decrypt(String source, String password) {

        String[] tokens = source.split(";");

        if (tokens.length != 4) {
            return null;
        }

        String header = tokens[0].trim();
        String salt = tokens[1].trim();
        String iv_base64 = tokens[2].trim();
        String ciphertext_base64 = tokens[3].trim();

        if (!header.equals(MESSAGE_HEADER)) {
            return null;
        }

        byte[] iv = Base64.decodeBase64(iv_base64);
        byte[] ciphertext = Base64.decodeBase64(ciphertext_base64);

        byte[] plaintext;

        try {
            plaintext = aes.decrypt(
                    new AESEncryptedMessage(salt, iv, ciphertext), password);
        } catch (EncryptionException ex) {
            return null;
        }
        
        plaintext = Compression.decompress(plaintext);

        if (plaintext == null)
            return null;
        
        String message = new String(plaintext, Charsets.UTF_8);
        return message;

    }
    
}
